/*
 * ESP32-P4 FL7703 LCD Driver (RGB565/RGB888)
 */

#pragma once

#include <stdbool.h>
#include "esp_lcd_types.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_mipi_dsi.h"
#include "hal/mipi_dsi_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief LCD panel IO handle (MIPI-DSI)
 */
#define FL7703_PANEL_IO_DBI_CONFIG()             \
    {                                            \
        .virtual_channel = 0,                    \
        .lcd_cmd_bits = 8,                       \
        .lcd_param_bits = 8,                     \
    }

/**
 * @brief FL7703 panel bus configuration (MIPI-DSI, 2 data lanes)
 */
#define FL7703_PANEL_BUS_DSI_2CH_CONFIG()                      \
    {                                                          \
        .bus_id = 0,                                           \
        .num_data_lanes = 2,                                   \
        .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,           \
        .lane_bit_rate_mbps = 750,                             \
    }

/**
 * @brief MIPI DPI configuration structure for FL7703 (RGB565/RGB888)
 * Based on vendor configuration: HFP=106, HBP=120, HSA=60, VFP=20, VBP=20, VSA=4
 *
 * @note  refresh_rate = (dpi_clock_freq_mhz * 1000000) / (h_res + hsync_pulse_width + hsync_back_porch + hsync_front_porch)
 *                                                      / (v_res + vsync_pulse_width + vsync_back_porch + vsync_front_porch)
 *
 */
#define FL7703_720_720_PANEL_CONFIG() \
    {                                                    \
        .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,     \
        .dpi_clock_freq_mhz = 50,                        \
        .virtual_channel = 0,                            \
        .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,   \
        .num_fbs = 1,                                    \
        .video_timing = {                                \
            .h_size = 720,                               \
            .v_size = 720,                               \
            .hsync_back_porch = 120,                     \
            .hsync_pulse_width = 60,                     \
            .hsync_front_porch = 106,                    \
            .vsync_back_porch = 20,                      \
            .vsync_pulse_width = 4,                      \
            .vsync_front_porch = 20,                     \
        },                                               \
        .flags.use_dma2d = false,                        \
    }

/**
 * @brief Type of LCD panel
 */
#define FL7703_PANEL_MINOR_VER_LATEST (-1)  /*!< Latest version */

/**
 * @brief FL7703 LCD initialization command structure
 */
typedef struct {
    int cmd;                /*<! The specific LCD command */
    const void *data;       /*<! Buffer that holds the command specific data */
    size_t data_bytes;      /*<! Size of `data` in memory, in bytes */
    unsigned int delay_ms;  /*<! Delay in milliseconds after this command */
} fl7703_lcd_init_cmd_t;

/**
 * @brief FL7703 vendor configuration structure
 */
typedef struct {
    const fl7703_lcd_init_cmd_t *init_cmds;      /*!< Pointer to initialization commands array */
    uint16_t init_cmds_size;                     /*!< Number of commands in above array */
    struct {
        unsigned int use_mipi_interface: 1;      /*!< Use MIPI interface to send LCD commands */
    } flags;
    struct {
        esp_lcd_dsi_bus_handle_t mipi_dsi_bus;   /*!< MIPI-DSI bus handle */
        esp_lcd_dpi_panel_config_t *dpi_config; /*!< MIPI-DPI panel configuration */
    } mipi_config;
} fl7703_vendor_config_t;

/**
 * @brief FL7703NI vendor specific initialization commands (2-lane DSI optimized)
 */
extern const fl7703_lcd_init_cmd_t fl7703ni_init_cmds[];
extern const uint16_t fl7703ni_init_cmds_size;

/**
 * @brief Get FL7703NI default initialization configuration
 * 
 * @param[out] init_cmds Pointer to initialization commands array
 * @param[out] init_cmds_size Size of the commands array
 */
void fl7703_get_default_init_config(const fl7703_lcd_init_cmd_t **init_cmds, uint16_t *init_cmds_size);

/**
 * @brief Create vendor config with FL7703NI default initialization
 * 
 * @param[in] dsi_bus_handle MIPI-DSI bus handle
 * @param[in] dpi_config_ptr MIPI-DPI panel configuration pointer
 * @return fl7703_vendor_config_t structure with default FL7703NI init
 */
#define FL7703_VENDOR_CONFIG_DEFAULT(dsi_bus_handle, dpi_config_ptr) \
    {                                                                 \
        .init_cmds = fl7703ni_init_cmds,                              \
        .init_cmds_size = fl7703ni_init_cmds_size,                    \
        .flags = {                                                    \
            .use_mipi_interface = 1,                                  \
        },                                                            \
        .mipi_config = {                                              \
            .mipi_dsi_bus = dsi_bus_handle,                           \
            .dpi_config = dpi_config_ptr,                             \
        },                                                            \
    }

/**
 * @brief Create LCD panel for model FL7703
 *
 * @param[in] io LCD panel IO handle
 * @param[in] panel_dev_config general panel device configuration
 * @param[out] ret_panel Returned LCD panel handle
 * @return
 *          - ESP_ERR_INVALID_ARG   if parameter is invalid
 *          - ESP_ERR_NO_MEM        if out of memory
 *          - ESP_OK                on success
 */
esp_err_t esp_lcd_new_panel_fl7703(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);

#ifdef __cplusplus
}
#endif 